/**
 * Copyright (c) 2009  Collaborative Development Group, C.S. Dept., University of Bari
 *
 * All rights reserved. This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0  which accompanies this distribution, and is 
 * available at http://www.eclipse.org/legal/epl-v10.html
 */
package it.uniba.di.cdg.penelope.ui.job;

import static org.osgi.service.log.LogService.LOG_DEBUG;
import static org.osgi.service.log.LogService.LOG_ERROR;

import java.lang.reflect.Field;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.osgi.service.log.LogService;

import com.google.inject.Inject;

/**
 * Intercept methods marked by {@link RunAsJob} and launch them asynchronously using the Eclipse Job API.
 */
public class JobExecutorInterceptor implements MethodInterceptor {
	
	@Inject
	private LogService logger;
	
	/* (non-Javadoc)
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	@Override
	public Object invoke( final MethodInvocation invocation ) throws Throwable {
		final RunAsJob ann = invocation.getMethod().getAnnotation( RunAsJob.class );

		// This is required to avoid recursive invocation (see #18)
		Field field = invocation.getClass().getDeclaredField( "index" );
		try {
			field.setAccessible( true );
			field.setInt( invocation, field.getInt( invocation ) + 1 );
		} finally {
			field.setAccessible( false );
		}

		Job job = new Job( ann.value() ) {
			@Override
			protected IStatus run( IProgressMonitor monitor ) {
				logger.log( LOG_DEBUG, "Running job: " + ann.value() );
				try {
					invocation.proceed();
					logger.log( LOG_DEBUG, String.format( "Job: \"%s\" concluded.", ann.value() ) );
				} catch (Throwable e) {
					logger.log( LOG_ERROR, String.format(  "[%s] %s", e.getClass().getName(), e.getMessage() ) );
					throw new JobExecutionException( e.getCause() );
				}
				
				return Status.OK_STATUS;
			}
			
		}; 
		job.schedule();
		
		return null;
	}
}
